% 默认页面大小 4:3
% \documentclass[10pt]{ctexbeamer}
% 页面大小 16:10
% \documentclass[10pt, aspectratio=1610]{ctexbeamer}
% 页面大小 16:9
\documentclass[10pt, aspectratio=169]{ctexbeamer}
% 页面大小 14:9
% \documentclass[10pt, aspectratio=149]{ctexbeamer}
% 页面大小 1.41:1
% \documentclass[10pt, aspectratio=141]{ctexbeamer}
% 页面大小 5:4
% \documentclass[10pt, aspectratio=54]{ctexbeamer}
% 页面大小 3:2
% \documentclass[10pt, aspectratio=32]{ctexbeamer}

\usetheme[logo=UCAS, sublogo=UCAS]{ucas}
% logo 的选项: CAS, UCAS
% sublogo 的选项: AMSS, AMSS2018, UCAS

% 引入参考文献列表的 .bib 文件, 使用 GB/T 7714-2015 的文献著录规则.
\usepackage[backend=biber, style=gb7714-2015]{biblatex}
\usepackage{listings}
\addbibresource{ref.bib}

\title[高级操作系统课程期中汇报]{高级操作系统课程期中汇报}
\subtitle[iSula源码阅读]{iSula源码阅读}
\author[姚益祁、王春祥、李小龙]{\href{mailto:timwcx@qq.com}{姚益祁、王春祥、李小龙}}
\date[\today]{\today, 中国南京}
\subject{iSula源码阅读}
\keywords{iSula, osCourse}

\begin{document}

\begin{frame}[plain]
  \maketitle
\end{frame}

\section[sandbox模块]{sandbox模块}
\begin{frame}{sandbox是什么？}
  在维基百科的描述中，sandbox是一种安全机制，为程序的执行提供隔离环境就是sandbox。

  也就是说，下面这些都可以是sandbox：
  \begin{itemize}
    \item 容器
    \item 虚拟机
    \item 设置安全规则的系统（SELinux）
    \item \ldots
  \end{itemize}
\end{frame}
\begin{frame}{sandbox是什么？}
  iSulad作为一个容器引擎，是与docker平行的管理容器的工具，在它之上有Kubernetes (K8s)作为容器集群的管理工具。

  在K8s这个容器编排引擎中，基本的管理单元叫作Pod，一个Pod内可以包含多个容器，K8s就是一个管理Pod的自动化工具。
  \begin{figure}
    \includegraphics[width=.9\textwidth, height=.6\textheight, keepaspectratio]{./figures/sandbox/Docker-Kubernetes-together.png}
  \end{figure}
\end{frame}

\begin{frame}[fragile]{sandbox是什么？}
  实际上，K8s的野心很大，不光希望支持管理容器集群，也希望能够支持虚拟机集群管理。为此，它需要一个新的概念——PodSandbox就此产生。

  它表示容器/虚拟机的资源分配的基本单元，不同的PodSandbox之间资源彼此隔离，内部则共享。

  这个PodSandbox的概念在CRI (Container Runtime Interface)中体现为RPC接口名称：
  \begin{lstlisting}[basicstyle=\ttfamily]
        rpc RunPodSandbox(RunPodSandboxRequest) 
          returns (RunPodSandboxResponse) {}
        rpc StopPodSandbox(StopPodSandboxRequest) 
          returns (StopPodSandboxResponse) {}
        rpc RemovePodSandbox(RemovePodSandboxRequest) 
          returns (RemovePodSandboxResponse) {}
  \end{lstlisting}
  由此，iSulad的sandbox的概念也才浮出水面：
  \begin{center}
    在只支持容器的情况下\textbf{本质上来说是Pod管理}，由CRI接口向K8s提供管理Pod能力。
  \end{center}
\end{frame}

\begin{frame}[fragile]{sandbox是如何实现的？}
  \begin{columns}
    \column{0.5\textwidth}
    在isulad中，有两种sandbox的控制器：
    \begin{itemize}
      \item shim
      \item sandboxer
    \end{itemize}

    前者利用pause容器的接口将sandbox管理请求转发给executor；

    后者有单独的sandboxer进程管理底层沙箱逻辑，sandboxer控制器通过gRPC请求实现控制
    \column{0.5\textwidth}
    \begin{figure}
      \includegraphics[width=\textwidth]{figures/sandbox/sandbox_module.png}
    \end{figure}
  \end{columns}
\end{frame}

\begin{frame}[fragile]{sandbox是如何实现的？}
  iSulad对K8s提供CRI的支持，自然可以从CRI的入口处的rpc执行流了解到详细的实现过程

  将以shim控制器为例，从下面的函数窥探其内部实现
  \begin{lstlisting}[basicstyle=\ttfamily]
    rpc RunPodSandbox(RunPodSandboxRequest)
      returns (RunPodSandboxResponse) {}
    message RunPodSandboxRequest {
        PodSandboxConfig config = 1;
        string runtime_handler = 2;
    }
  \end{lstlisting}
\end{frame}

\begin{frame}{sandbox是如何实现的？}
  \begin{columns}
    \column{0.6\textwidth}
      如右图所示，RunPodSandbox内部执行过程总体上可以分解为这些方法
      \begin{itemize}
        \item PrepareSandboxData
        \item EnsureSandboxImageExists
        \item PrepareSandboxCheckpoint
        \item UpdateSandboxConfig
        \item PrepareSandboxKey
        \item SandboxManager::CreateSandbox 
        \item SetupSandboxNetwork
        \item Sandbox::Create
        \item Sandbox::Start
        \item Sandbox::UpdateNetworkSettings
      \end{itemize}
    \column{0.4\textwidth}
    \begin{figure}
      \includegraphics[width=\textwidth, height=.8\textheight, keepaspectratio]{figures/sandbox/RunPodSandbox.png}
    \end{figure}
  \end{columns}
\end{frame}

\begin{frame}{sandbox是如何实现的？}
  \begin{columns}
    \column{0.6\textwidth}
    下面以shim controller为例，分析上述流程的关键步骤

    \begin{itemize}
      \item PrepareSandboxData
      \item SandboxManager::CreateSandbox
      \item Sandbox::Create
      \item Sandbox::Start
    \end{itemize}
    \column{0.4\textwidth}
    \begin{figure}
      \includegraphics[width=\textwidth, height=.8\textheight, keepaspectratio]{figures/sandbox/RunPodSandbox.png}
    \end{figure}
  \end{columns}
\end{frame}

\begin{frame}[fragile]{sandbox是如何实现的？}
  \begin{block}{PrepareSandboxData}
    将RPC传入的config数据转化为iSulad中的配置信息的内部变量

    config包括如下配置信息：
  \begin{itemize}
    \item 要创建的sandbox名
    \item sandbox的uid
    \item namespace
    \item label字典（key-value的map）
    \item Linux特有的PodSandboxConfig
    \item Windows特有的PodSandboxConfig
    \item \ldots
  \end{itemize}
  注：有一个由iSulad配置文件确定的podSandboxImage镜像，用以创建该sandbox内的管理容器
  \end{block}
\end{frame}

\begin{frame}[fragile]{sandbox是如何实现的？}
  \begin{block}{SandboxManager::CreateSandbox}
    做好检查后调用new Sandbox创建Sandbox类的对象实例
    \begin{lstlisting}[language=C++, basicstyle=\ttfamily, keywordstyle=\color{blue}]
    sandbox = std::shared_ptr<Sandbox>(new Sandbox(id, m_rootdir, 
    m_statedir, name, info, netMode, netNsPath, 
    sandboxConfig, image));
    sandbox->SetController(controller);
    /// 创建相关的文件夹
    sandbox->PrepareSandboxDirs(error);
    /// 将id与sandbox指针/sandbox name的映射保存在Sandbox成员中
    SaveSandboxToStore(id, sandbox);
    \end{lstlisting}
  \end{block}
\end{frame}

\begin{frame}[fragile]{sandbox是如何实现的？}
  \begin{block}{Sandbox::Create}
    \begin{columns}
      \column{.5\textwidth}
      \begin{lstlisting}[language=C++, basicstyle=\ttfamily\tiny, keywordstyle=\color{blue}]
    auto Sandbox::Create(Errors &error) -> bool {
        struct ControllerCreateParams params;
        params.config = m_sandboxConfig;
        params.netNSPath = m_netNsPath;
        params.sandboxName = m_name;
        params.image = m_image;
        /// ...
        if (!m_controller->Create(m_id, params, error)) {
          /// ...
            return false;
        }
        return true;
    }
      \end{lstlisting}
      \column{.5\textwidth}
      \begin{lstlisting}[language=C++, basicstyle=\ttfamily\tiny, keywordstyle=\color{blue}]
bool ShimController::Create
  (const std::string &sandboxId, const ControllerCreateParams &params,
      Errors &error) {
  /// error handling...
  auto requestWrapper = GenerateSandboxCreateContainerRequest
      (sandboxId, params, error);
  if (error.NotEmpty()) {
    return false;
  }
  container_create_response * response {nullptr};
  int ret = m_cb->container.create(requestWrapper->get(), &response);
  /// error handling...
  if (ret != 0) {
    /// error handling...
  }
  return error.Empty();
}
      \end{lstlisting}
    \end{columns}
    \begin{center}
      m\_cb是iSulad全局的executor在ShimController中的指针，利用它执行RPC调用
      \begin{lstlisting}[language=C++, basicstyle=\ttfamily\small, keywordstyle=\color{blue}]
      g_isulad_service_executor->container.create()
      \end{lstlisting}
      以对应容器的创建最终完成sandbox创建
    \end{center}
  \end{block}
\end{frame}

\begin{frame}[fragile]{sandbox是如何实现的？}
  \begin{block}{Sandbox::Start}
    调用`Controller`的Start方法，会调用`ShimController`的Start，最终同样调用了executor的接口
    \begin{lstlisting}
      g_isulad_service_executor->container.start()
    \end{lstlisting}
    完成启动容器
  \end{block}
  \begin{block}{总结}
    sandbox模块实现了管理Pod资源隔离，当使用shim controller时，最终的管理都调用了executor的接口以对容器操作的方式进行
  \end{block}
\end{frame}

\section[network模块]{network模块}

\begin{frame}{容器网络模式}
  容器网络模式包括Host模式、Container模式、None模式和Bridge模式。
  \begin{figure}
    \includegraphics[width=.9\textwidth, height=.9\textheight, keepaspectratio]{./figures/network/docker_network.png}
  \end{figure}
\end{frame}

\begin{frame}{容器网络管理}
  \begin{columns}
    \column{0.4\textwidth}
    \begin{block}{创建Bridge网桥需要的操作}
      \begin{itemize}
        \item 创建接口（物理网络接口和虚拟网络接口）
        \item 创建 veth 对
        \item 设置命名空间网络
        \item 设置静态路由
        \item 配置以太网桥（eth bridge）
        \item 分配 IP 地址
        \item 创建 NAT 规则
        \item \ldots
      \end{itemize}
    \end{block}
    \column{0.6\textwidth}
    \begin{figure}
      \includegraphics[width=.8\textwidth, height=.8\textheight, keepaspectratio]{./figures/network/create_veth.png}
    \end{figure}
  \end{columns}
\end{frame}

\begin{frame}{CNI (Container Network Interface)-容器网络接口}
  \begin{block}{什么是CNI？}
    CNI是K8s 中标准的调用网络实现的接口。Kubelet 通过这个标准的接口来调用不同的网络插件以实现不同的网络配置方式。

    CNI网络插件是一个可执行文件，是遵守容器网络接口（CNI）规范的网络插件。常见的 CNI网络插件包括 Calico、flannel、Terway、Weave Net等。
  \end{block}
  \begin{figure}
    \includegraphics[width=.7\textwidth, height=.7\textheight, keepaspectratio]{./figures/network/k8s&cni.png}
  \end{figure}
\end{frame}

\begin{frame}{如何使用CNI插件进行容器网络配置}
  \begin{columns}
    \column{0.4\textwidth}
    \begin{block}{mynet.json}
      \{ \\
      \, \,"cniVersion": "0.4.0", \\
      \, \,"name": "mynet", \\
      \, \,"type": "bridge",  \\
      \, \,"bridge": "cni0", \\
      \, \,"isGateway": true, \\
      \, \,"ipMasq": true, \\
      \, \,"ipam": \{ \\
      \, \, \, \,  "type": "host-local", \\
      \, \, \, \,  "subnet": "172.19.0.0/24", \\
      \, \, \, \,  "routes": [ \{ "dst": "0.0.0.0/0" \} ] \\
      \, \, \} \\
      \} \\
    \end{block}
    \column{0.6\textwidth}
    \begin{figure}
      \includegraphics[width=.8\textwidth, height=.8\textheight, keepaspectratio]{./figures/network/cni-how-is-working-1.png}
    \end{figure}
  \end{columns}
\end{frame}

\begin{frame}{如何使用CNI插件进行容器网络配置}
  \begin{block}{如何使用CNI插件进行容器网络配置}
    \texttt{cat mynet.json | CNI\_PATH=/opt/cni/bin} \\
    \texttt{\textbackslash{} CNI\_CONTAINERID=net1} \\
    \texttt{\textbackslash{} CNI\_NETNS=/var/run/netns/net1} \\
    \texttt{\textbackslash{} CNI\_IFNAME=eth0} \\
    \texttt{\textbackslash{} CNI\_COMMAND=ADD} \texttt{/opt/cni/bin/bridge}
  \end{block}
  \begin{figure}
    \includegraphics[width=.9\textwidth, height=.9\textheight, keepaspectratio]{./figures/network/test_cni_9.png}
  \end{figure}
\end{frame}

\begin{frame}{network模块}
  \begin{figure}
    \includegraphics[width=.99\textwidth, height=.99\textheight, keepaspectratio]{./figures/network/network_arch.png}
  \end{figure}
\end{frame}

\begin{frame}{Network attach样例}
  Network 连接执行过程展示
\end{frame}

\begin{frame}[plain]
  \vfill
  \centerline{\Huge 谢谢}
  \vfill
\end{frame}

\end{document}
